package dynaspring.web;

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.Resource;
import org.springframework.web.context.support.AbstractRefreshableWebApplicationContext;

import dynaspring.Configuration;
import dynaspring.LispBeanDefinitionReader;
import dynaspring.LispBeanFactory;

public class LispWebApplicationContext extends AbstractRefreshableWebApplicationContext {

	/** Default config location for the root context */
	public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.lisp";
	
	/** Default prefix for building a config location for a namespace */
	public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
	
	/** Default suffix for building a config location for a namespace */
	public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".lisp";
	
	public static final String DYNASPRING_CONFIGURATION_LOCATION_PARAMETER = "dynaspringConfiguration";

	private static final Log log = LogFactory.getLog(LispWebApplicationContext.class);
	private Configuration configuration = new Configuration();
	
	public LispWebApplicationContext() {
		PropertyPlaceholderConfigurer c = new PropertyPlaceholderConfigurer();
		c.setProperties(configuration);
		addBeanFactoryPostProcessor(c);
	}
	
	protected void loadConfiguration() {
		configuration.reset();
		String conf = getServletContext().getInitParameter(DYNASPRING_CONFIGURATION_LOCATION_PARAMETER);
		if(conf != null) {
			String[] paths = conf.split(",");
			for(final String path : paths) {
				try {
					configuration.pushConfiguration(path.trim(), this);
				} catch (IOException e) {
					log.error("Couldn't load configuration from " + path.trim(), e);
					throw new RuntimeException(e);
				}
			}
		}
		configuration.getVariables().put("spring::*application-context*", this);
	}
	
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		loadConfiguration();
		super.refresh();
	}
	
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory factory) throws IOException {
		log.info("Loading bean definitions");
		for(String location : getConfigLocations()) {
			loadBeanDefinitions(getResource(location), factory);
		}
	}
	
	public void loadBeanDefinitions(Resource res, DefaultListableBeanFactory factory) throws IOException {
		LispBeanDefinitionReader reader = new LispBeanDefinitionReader(factory, configuration);
		//Configure the bean definition reader with this context's resource loading environment.
		reader.setResourceLoader(this);
		reader.loadBeanDefinitions(res);
	}
	
	@Override
	protected String[] getDefaultConfigLocations() {
		if (getNamespace() != null) {
			return new String[] { DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX };
		} else {
			return new String[] { DEFAULT_CONFIG_LOCATION };
		}
	}
	
	@Override
	protected DefaultListableBeanFactory createBeanFactory() {
		return new LispBeanFactory(getInternalParentBeanFactory());
	}

}
